﻿//*************************************************************************************************
// ContentHandler.cs
// Owner: Mahipal Kante
//
// Base class for handling a content type
//
// Copyright(c) Microsoft Corporation, 2010
//*************************************************************************************************
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.IO;
using System.Xml.XPath;

namespace WebTest.WebService.Plugin.Runtime
{
    /// <summary>
    /// Base class for handling a content type
    /// </summary>
    public class ContentHandler
    {
        private string xmlString = string.Empty;
        private XmlDocument xmlDocument = null;

        /// <summary>
        /// Is it a binary format?
        /// </summary>
        public virtual bool IsBinary
        {
            get
            {
                return false;
            }
        }

        /// <summary>
        /// Raw binary content
        /// </summary>
        public virtual Byte[] MessageBytes 
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        /// <summary>
        /// Raw string content
        /// </summary>
        public virtual string MessageString
        {
            get
            {
                return XmlToString(this.XmlDocument);
            }
            set
            {
                this.xmlString = value;
                this.xmlDocument = null;
            }
        }

        /// <summary>
        /// message converted to XML
        /// </summary>
        public string XmlString
        {
            get
            {
                return XmlToIndentedString(this.XmlDocument);
            }
            set
            {
                this.xmlString = value;
                this.xmlDocument = null;
            }
        }

        /// <summary>
        /// XML Document of the message
        /// </summary>
        public XmlDocument XmlDocument
        {
            get
            {
                if (this.xmlDocument == null)
                {
                    if (string.IsNullOrEmpty(this.xmlString))
                    {
                        this.LoadDocument();
                    }
                    else
                    {
                        try
                        {
                            this.xmlDocument = new XmlDocument();
                            this.xmlDocument.LoadXml(this.xmlString);
                        }
                        catch (Exception)
                        {
                            // Try setting it as a native format message
                            this.MessageString = this.xmlString;
                            this.LoadDocument();
                        }
                    }
                }

                return xmlDocument;
            }
            set
            {
                this.xmlDocument = value;
            }
        }

        /// <summary>
        /// XPath document of XML
        /// </summary>
        public virtual XPathDocument XPathDocument
        {
            get
            {
                return new XPathDocument(new StringReader(this.xmlString));
            }
        }

        /// <summary>
        /// Evaluates XPath
        /// </summary>
        /// <param name="xPath">xPath expression</param>
        /// <returns></returns>
        public XPathNodeIterator EvaluateXPath(string xPath)
        {
            XPathDocument x = this.XPathDocument;
            XPathNavigator nav = x.CreateNavigator();
            XmlNamespaceManager context = new XmlNamespaceManager(nav.NameTable);
            while (nav.MoveToFollowing(XPathNodeType.Element))
            {
                IDictionary<string, string> whatever = nav.GetNamespacesInScope(XmlNamespaceScope.All);
                foreach (KeyValuePair<string, string> key in whatever)
                {
                    context.AddNamespace(key.Key, key.Value);
                }
            }

            // Compile a standard XPath expression
            XPathExpression expr;
            expr = nav.Compile(xPath);
            expr.SetContext(context);
            return nav.Select(expr);
        }

        /// <summary>
        /// Override to perform custom load
        /// </summary>
        protected virtual void LoadDocument()
        {
        }

        /// <summary>
        /// Converts XmlDocument to String
        /// </summary>
        /// <param name="dom"></param>
        /// <returns></returns>
        public static string XmlToString(XmlDocument dom)
        {
            string message = string.Empty;
            System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
            using (var stream = new MemoryStream())
            {
                using (XmlTextWriter writer = new XmlTextWriter(stream, encoding))
                {
                    dom.WriteTo(writer);
                }
                message = encoding.GetString(stream.ToArray());
            }

            return message;
        }

        /// <summary>
        /// Converts XmlDocument to String
        /// </summary>
        /// <param name="dom"></param>
        /// <returns></returns>
        public static string XmlToIndentedString(XmlDocument dom)
        {
            string message = string.Empty;
            System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
            using (var stream = new MemoryStream())
            {
                using (XmlTextWriter writer = new XmlTextWriter(stream, encoding))
                {
                    writer.Formatting = Formatting.Indented;
                    dom.WriteTo(writer);
                }
                message = encoding.GetString(stream.ToArray());
            }

            return message;
        }

        /// <summary>
        /// Parses XML in string form and returns XmlDocument
        /// </summary>
        /// <param name="xmlString"></param>
        /// <returns></returns>
        public static XmlDocument StringToXml(string xmlString)
        {
            XmlDocument dom = new XmlDocument();
            dom.LoadXml(xmlString);
            return dom;
        }
    }
}
